import os


from command_parser.ld_parse.ld_option_dict import *
from command_parser.option_base import *


                            
                            
def get_simple_option(option="", option_dict={}):
    
    if not option or not option_dict:
        return None
     
    attribute = option_dict.get(option, None)
    
    if attribute is None:
        return None
    
    category = attribute["category"]
    keep = attribute["support"]
    
    return Option(option=option, parameter=[], type=PREFIX_SIMPLE, category=category, keep=keep)


def get_equal_option(option="", option_dict={}):
    
    if not option or not option_dict:
        return None
    
    if '=' not in option:
        return None
    
    [prefix, param] = option.split('=', 1)
    attribute = option_dict.get(prefix, None)
    if attribute is None:
        return None
    
    category = attribute["category"]
    keep = attribute["support"]
    
    return Option(option=prefix, parameter=[param], type=PREFIX_EQUAL, category=category, keep=keep)


def get_match_option(option="", option_dict={}):
    if not option or not option_dict:
        return None
    
    for prefix, attribute in list(option_dict.items()):
        if option.startswith(prefix):
            param = option[len(prefix):]
            
            category = attribute["category"]
            keep = attribute["support"]
            
            return Option(option=prefix, parameter=[param], type=PREFIX_MATCH, category=category, keep=keep)

def get_space_option(prefix="", params="", option_dict={}):
    
    if params is None or not option_dict:
        return None
    
    attribute = option_dict.get(prefix, None)
    if attribute is None:
        return None
    
    category = attribute["category"]
    keep = attribute["support"]
    
    return Option(option=prefix, parameter=[params], type=PREFIX_SPACE, category=category, keep=keep)

def get_unknown_option(option="", next_opt="", OptionCategory=None):
    # TODO: need to handle OptionCategory
    attribute = {"support": False, "category": OptionCategory.UNKNOWN}
    
    category = attribute["category"]
    keep = attribute["support"]

    if '=' in option:       
        equal_index = option.index('=')
        opt = option[0:equal_index]
        param = option[equal_index + 1:]
        return Option(opt, [param], PREFIX_EQUAL, category=category, keep=keep)
    elif (not next_opt) or next_opt[0] == '-' or os.path.isfile(next_opt): 
        return Option(option, [], PREFIX_SIMPLE, category=category, keep=keep)
    else:
        return Option(option, [next_opt], PREFIX_SPACE, category=category, keep=keep)
        
    
def parse_at_option(options=[]):
    new_options = []
    
    for option in options:
        
        if not option.startswith('@'):
            new_options.append(option)
            continue
        
        opt_file = option[1:]
        try:
            with open(opt_file, 'r') as f:
                at_options_str = f.read()
                at_options = split_at_options(at_options_str)
                new_options.extend(parse_at_option(at_options));
        except Exception:
            new_options.append(option)
    return new_options

def split_at_options(options_str=[]):

    at_options = []
    option = ""
    is_escape = False
    quote = ''
    for char in options_str:
        if is_escape:
            ''.join(option, char)
            is_escape = False
        elif char is '\\':
            is_escape = True
        elif char is '\"' or char is '\'':
            if quote is char:
                quote = ''
            elif quote is '':
                quote = char
            else:
                ''.join(option, char)
        elif char.isspace() and not quote:
            if option:
                at_options.append(option)
                option = ""
        else:
            ''.join(option, char)
    
    if option:
        at_options.append(option)
        
    return at_options

def split_pass_option(options=[]):
    cmd = []
    for opt, next_opt in zip(options, options[1:] + [None]):
        if opt.option == '' and opt.parameter == []:
            pass
        elif opt.option == '-Wl,':
            cmd += parse_Wl_option(opt, next_opt)
        elif opt.option == '-Wa,':
            cmd += parse_Wa_option(opt)
        elif opt.option == '-Wp,':
            cmd += parse_Wp_option(opt)
        else:
            cmd.append(opt)
    return cmd

def parse_Wl_option(opt="", next_opt=""):
    cmd = []
    raw_options = opt.parameter[0].split(',')
    i = 0

    ld_space_dict = OptionDict(option_dict_xml).get_space_dict()
    
    while i < len(raw_options):
        raw_opt = raw_options[i]
        if raw_opt not in ld_space_dict:
            # opt haven't space argument
            cmd.append(Option(opt.option, [raw_opt], opt.type, opt.category, opt.keep))
        elif i+1 < len(raw_options):
            # opt have a space argument after commas
            cmd.append(Option(opt.option, [raw_opt], opt.type, opt.category, opt.keep))
            cmd.append(Option(opt.option, [raw_options[i + 1]], opt.type, opt.category, opt.keep))
            i += 1
        elif not next_opt:
            # opt is the last option in Wl, but haven't argument
            cmd.append(Option(opt.option, [raw_opt], opt.type, opt.category, opt.keep))
        else:
            # opt have a argument in next_opt
            cmd.append(
                Option(opt.option, [raw_opt], opt.type, opt.category, opt.keep))
            cmd.append(
                Option(opt.option, next_opt.parameter, opt.type, opt.category, opt.keep))
            next_opt.option=''
            next_opt.parameter=[]
        i += 1
    return cmd

def parse_Wa_option(opt=""):
    cmd = []
    raw_options = opt.parameter[0].split(',')
    for i in range(len(raw_options)):
        raw_opt = raw_options[i]
        cmd.append(Option(opt.option, [raw_opt], opt.type, opt.category, opt.keep))

    return cmd

def parse_Wp_option(opt=""):
    cmd = []
    raw_options = opt.parameter[0].split(',')
    for i in range(len(raw_options)):
        raw_opt = raw_options[i]
        cmd.append(Option(opt.option, [raw_opt], opt.type, opt.category, opt.keep))

    return cmd